package com.sugon.modules.device.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.consts.DataAction;
import com.sugon.dao.DevMaintenRepairDao;
import com.sugon.dao.DevMaintenThirdpartyCbDao;
import com.sugon.dao.TicketLiveImageDao;
import com.sugon.entity.*;
import com.sugon.modules.alarm.service.AlarmCodeBaseService;
import com.sugon.modules.base.consts.CacheKeyPrefix;
import com.sugon.modules.device.consts.DevRepairTicketStage;
import com.sugon.modules.device.consts.DeviceTicketSource;
import com.sugon.modules.device.model.vo.DevRepairRecordVO;
import com.sugon.modules.device.service.IDeviceRepairManager;
import com.sugon.modules.sys.service.INoticeManager;
import com.sugon.modules.sys.service.ISysDeptManager;
import com.sugon.service.*;
import com.sugon.utils.ProcessInfoEnum;
import com.sugon.utils.ShiroUtils;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author ： YuXD
 * @description： 设备维修业务Manager实现类
 * @date ： 2020-08-13 下午 11:05
 * @version: 1.0
 */
@Service
public class DeviceRepairManagerImpl implements IDeviceRepairManager {

    @Autowired
    private DevMaintenWorkService devMaintenWorkService;
    @Resource
    private DevRepairRecordService deviceRepairRecordService;
    @Autowired
    private SysMsgService sysMsgService;
    @Autowired
    private ISysDeptManager deptService;
    @Autowired
    private DeviceInfoService deviceInfoService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DevMaintenRepairService devRepairRecordService;
    @Resource
    private DevRepairRecordService repairRecordService;
    @Autowired
    private DevMaintenRepairDao devMaintenRepairDao;
    @Autowired
    private DevReportUrgeService devReportUrgeService;
    @Autowired
    private INoticeManager noticeManager;
    @Resource
    private AlarmCodeBaseService alarmCodeBaseService;
    @Autowired
    private DevMaintenThirdpartyCbDao devMaintenThirdpartyCbDao;
    @Autowired
    private TicketLiveImageService ticketLiveImageService;
    @Resource
    private DevFaultPreventMeasureService devFaultPreventMeasureService;
    @Resource
    private TicketLiveImageDao ticketLiveImageDao;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteTicket(String ticketId) {
        // 1、先删除维修记录+维修换件记录
        DevMaintenRepairEntity repairRecord = devMaintenRepairDao.queryByTicketId(ticketId);
        if (repairRecord != null) {
            devRepairRecordService.delete(repairRecord.getId());
        }
        // 2、删除制定的预防措施&设备维护工单
        devFaultPreventMeasureService.deleteByRepairTicketId(ticketId);
        // 3、删除现场照片
        ticketLiveImageDao.deleteByTicket(null, ticketId, "REPAIR");
        // 4、删除维修工单
        devMaintenRepairDao.delete(ticketId);
    }

    /**
     * @param ticketId 维修工单ID
     * @param userId   用户ID
     * @return
     */
    @Override
    public synchronized boolean urge(String ticketId, String userId) {
        DevMaintenWorkEntity ticket = devMaintenWorkService.queryObject(ticketId);
        Assert.notNull(ticket, "维修工单不存在，工单ID: " + ticketId);
        // 1、更新维修工单状态
        ticket.setUrgeStatus(1);
        boolean flag = devMaintenWorkService.update(ticket) > 0;
        if (flag) {
            // 2、保存催办记录
            DevReportUrgeEntity devReportUrge = new DevReportUrgeEntity();
            devReportUrge.setUrgentlyUser(userId);
            devReportUrge.setUrgentlyTime(DateUtil.date());
            devReportUrge.setRepairNo(ticketId);
            devReportUrge.setTicketType("REPAIR");
            devReportUrgeService.save(devReportUrge);
            // 3、更新工单消息提醒
            sysMsgService.addRemindItem(ProcessInfoEnum.DEV_ZXGD, ticketId, null);
            // 4、给维修人员或维修组长发送催单消息
            noticeManager.pushDeviceCDNotice(ticketId);
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean confirmRepair(DevRepairRecordEntity devMaintenWork) {
        devMaintenWork.setDevStatus(DevRepairTicketStage.START_REPAIR);
        // 如果没有开始维修时间，那么设置为当前系统时间
        if (devMaintenWork.getRepairStartDate() == null) {
            devMaintenWork.setRepairStartDate(DateUtil.date());
        }
        // 1、更新设备维修工单状态和开始维修时间
        if (deviceRepairRecordService.update(devMaintenWork)) {

            /*
             开始维修后，根据不同时长会触发：车间维修工->车间机电设备工程师 -> 制造处工程师
             每个触发点默认为：30分钟 120分钟，每个产线会设置不同的触发时间
             0-30分 ，维修工可以自主点击上报，如到期没有点击，则系统自动上报
             30-120， 机电设备工程师可以自主点击上报，如到期没有点击，系统会自动触发
             */
            DeviceInfoEntity deviceInfo = deviceInfoService.queryObject(devMaintenWork.getDevId());
            if (deviceInfo != null) {
                // 设置车间协助自动触发机制
                Integer workshopTriggerTime = deptService.getWorkshopTriggerTime(deviceInfo.getDevProductCode());
                redisTemplate.opsForValue().set(CacheKeyPrefix.DRT_WORKSHOP_TRIGGER_PREFIX + devMaintenWork.getId(), workshopTriggerTime);
                redisTemplate.expire(CacheKeyPrefix.DRT_WORKSHOP_TRIGGER_PREFIX + devMaintenWork.getId(), workshopTriggerTime, TimeUnit.MINUTES);

                // 设置工厂协助自动触发机制
                Integer factoryTriggerTime = deptService.getFactoryTriggerTime(deviceInfo.getDevProductCode());
                redisTemplate.opsForValue().set(CacheKeyPrefix.DRT_FACTORY_TRIGGER_PREFIX + devMaintenWork.getId(), factoryTriggerTime);
                redisTemplate.expire(CacheKeyPrefix.DRT_FACTORY_TRIGGER_PREFIX + devMaintenWork.getId(), factoryTriggerTime, TimeUnit.MINUTES);
            }
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean perfectRepairRecord(DevRepairRecordEntity repairRecord) {
        // 更新工单状态
        if (DevRepairTicketStage.END_REPAIR.equals(repairRecord.getDevStatus())) {
            repairRecord.setDevStatus(DevRepairTicketStage.CLOSE);
        }
        // 更新是否制定预防措施
        List<DevFaultPreventMeasure> measureList = repairRecord.getPreventMeasureList();
        // 制定、更新或删除预防措施
        devFaultPreventMeasureService.formulatePreventMeasure(repairRecord, measureList);
        repairRecord.setIsPrevented(CollectionUtil.isNotEmpty(measureList) ? 1 : 0);
        // 更新维修记录
        return repairRecordService.update(repairRecord);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean perfectRepairRecord(DevMaintenRepairEntity repairRecord) {
        if (devRepairRecordService.update(repairRecord) > 0) {
            /*
                1、更新工单的维修人、工单状态以及是否制定预防措施等
                2、制定预防措施 如果有的话
             */
            DevMaintenWorkEntity repairWork = devMaintenWorkService.queryObject(repairRecord.getMaintenRecordId());
            if (repairWork == null) {
                repairWork = doAdditionalRecording(repairRecord);
            }
            // 更新维修人
            repairWork.setRepairUser(repairRecord.getRepairUser());
            // 更新工单状态
            if (DevRepairTicketStage.END_REPAIR.equals(repairWork.getDevStatus())) {
                repairWork.setDevStatus(DevRepairTicketStage.CLOSE);
            }
            // 更新是否制定预防措施
            List<DevFaultPreventMeasure> measureList = repairRecord.getPreventMeasureList();
            if (CollectionUtil.isNotEmpty(measureList)) {
                repairWork.setIsPrevented(1);
            } else {
                repairWork.setIsPrevented(0);
            }
            /*
                制定、更新或删除预防措施
             */
            //devFaultPreventMeasureService.formulatePreventMeasure(repairRecord, measureList);
            // 更新工单信息
            repairWork.setStartRepairTime(repairRecord.getRepairStartDate());
            repairWork.setEndRepairTime(repairRecord.getRepairEndDate());
            devMaintenWorkService.update(repairWork);
        }
        return true;
    }

    /**
     * completeRepair
     *
     * @param repairTicket 工单维修记录信息
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean completeRepair(DevRepairRecordEntity repairTicket) {
        // 1、更新维修工单状态和结束维修时间
        repairTicket.setDevStatus(DevRepairTicketStage.END_REPAIR);
        if (repairTicket.getRepairEndDate() == null) {
            repairTicket.setRepairEndDate(DateUtil.date());
        }
        if (deviceRepairRecordService.update(repairTicket)) {
            // 2、删除触发上级协助的缓存信息
            redisTemplate.delete(CacheKeyPrefix.DRT_WORKSHOP_TRIGGER_PREFIX + repairTicket.getId());
            redisTemplate.delete(CacheKeyPrefix.DRT_FACTORY_TRIGGER_PREFIX + repairTicket.getId());
        }
        return true;
    }

    /**
     * report
     *
     * @param repairTicket   工单
     * @param assistPersonId 协助人员ID
     * @return
     */
    @Override
    public boolean report(DevMaintenWorkEntity repairTicket, String assistPersonId) {
        String ticketId = repairTicket.getId();
        int nextHandleNode = repairTicket.getHandleNode() + 1;
        repairTicket.setProcessNode(nextHandleNode);
        if (devMaintenWorkService.update(repairTicket) > 0) {
            // 1、更新维修记录中协助相关信息并清除到期自动上报缓存
            DevMaintenRepairEntity repairRecord = devMaintenRepairDao.queryByTicketId(ticketId);
            if (repairRecord != null) {
                repairRecord.setOrderNo(nextHandleNode);
                if (nextHandleNode == 3) {
                    repairRecord.setLevel3AssistUser(assistPersonId);
                    repairRecord.setLevel3AssistStartTime(DateUtil.date());
                    // 清除自动上报到PE
                    redisTemplate.delete(CacheKeyPrefix.DRT_FACTORY_TRIGGER_PREFIX + ticketId);
                } else if (nextHandleNode == 2) {
                    repairRecord.setLevel2AssistUser(assistPersonId);
                    repairRecord.setLevel2AssistStartTime(DateUtil.date());
                    //  清除自动上报到车间机电设备工程师
                    redisTemplate.delete(CacheKeyPrefix.DRT_WORKSHOP_TRIGGER_PREFIX + ticketId);

                }
                // 更新维修工单信息
                devRepairRecordService.update(repairRecord);

            }
            // 2、向指定人员发送消息通知
            sysMsgService.addRemindItem(ProcessInfoEnum.DEV_ZXGD, ticketId, assistPersonId);
            // 3、更新工单超时状态为未超时
            repairTicket.setIsOvertime(0);
            devMaintenWorkService.update(repairTicket);
        }
        return true;
    }

    /**
     * loadDevRepairRecord
     *
     * @param devId 设备ID
     * @return
     */
    @Override
    public List<DevRepairRecordVO> loadDevRepairRecord(String devId) {
        List<DevRepairRecordVO> devRepairRecordList = devMaintenRepairDao.loadDevRepairRecord(devId);
        if (devRepairRecordList == null) {
            devRepairRecordList = new ArrayList<>();
        }
        return devRepairRecordList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public DevRepairRecordEntity handThirdPartyCallback(DevMaintenThirdpartyCbEntity callbackData) {
        DevRepairRecordEntity repairRecord = null;
        Integer repairStage = callbackData.getRepairStage();
        String action = callbackData.getAction();
        if (StrUtil.equals(DataAction.DELETE.name(), action)) {
            deleteTicket(callbackData.getErmsBusId());
        } else if (DevRepairTicketStage.CALL_REPAIR.equals(repairStage) || StrUtil.equals(DataAction.ADD.name(), action)) {
            DeviceInfoEntity device = deviceInfoService.queryObject(callbackData.getDevId());
            cn.hutool.core.lang.Assert.notNull(device);
            repairRecord = new DevRepairRecordEntity();
            repairRecord.setWorkshopId(device.getDevFarm());
            repairRecord.setDevId(device.getId());
            repairRecord.setUploadId(callbackData.getUploader());
            repairRecord.setUploadDate(callbackData.getUploadTime());
            repairRecord.setDevStatus(DevRepairTicketStage.CALL_REPAIR);
            repairRecord.setSource(DeviceTicketSource.HMI.name());
            repairRecord.setCreateBy("一键报修");
            repairRecord.setFaultCode(callbackData.getFaultDesc());
            repairRecord.setFaultDesc(callbackData.getFaultDesc());
            // 如果故障报警代码不为空，则校验报警代码是否存在，如果存在则设置报警分类和报警ID
            if (StrUtil.isAllNotEmpty(callbackData.getDevId(), callbackData.getFaultCode())) {
                AlarmCodeBaseEntity matchedAlarmCode = alarmCodeBaseService.query(null, callbackData.getDevId(), callbackData.getFaultCode());
                if (matchedAlarmCode != null) {
                    repairRecord.setFaultId(matchedAlarmCode.getId());
                    repairRecord.setFaultCategoryId(matchedAlarmCode.getAlarmCategoryId());
                    repairRecord.setUpdateBy("一键报修");
                }
            }
            boolean callRepairResult = deviceRepairRecordService.save(repairRecord);
            if (callRepairResult) {
                // 设置ermsBusId，为后续识别做准备
                callbackData.setErmsBusId(repairRecord.getId());
                devMaintenThirdpartyCbDao.updateErmsBusId(callbackData.getId(), repairRecord.getId());
            }
        } else if (DevRepairTicketStage.START_REPAIR.equals(repairStage)) {
            String ermsBusId = callbackData.getErmsBusId();
            cn.hutool.core.lang.Assert.isTrue(StrUtil.isNotEmpty(ermsBusId));
            repairRecord = deviceRepairRecordService.queryObject(ermsBusId);
            Assert.notNull(repairRecord);
             /*
                由于已经出现了操作工误操作导致的维修开始信号，晚于维修结束信号到来的场景
                所以收到开始维修信号时不处理已结束的模具维修工单
             */
            if (NumberUtil.equals(DevRepairTicketStage.END_REPAIR, repairRecord.getDevStatus())) {
                return repairRecord;
            }
            // 如果出现了更新，那么需要更新下故障代码之类的
            if (StrUtil.equals(DataAction.UPDATE.name(), action)) {
                //TODO
            }
            repairRecord.setRepairStartDate(callbackData.getStartRepairTime());
            confirmRepair(repairRecord);
        } else if (DevRepairTicketStage.END_REPAIR.equals(repairStage)) {
            String ermsBusId = callbackData.getErmsBusId();
            cn.hutool.core.lang.Assert.isTrue(StrUtil.isNotEmpty(ermsBusId));
            repairRecord = deviceRepairRecordService.queryObject(ermsBusId);
            Assert.notNull(repairRecord);
            // 如果出现了更新，那么需要更新下故障代码、描述、开始维修时间
            if (StrUtil.equals(DataAction.UPDATE.name(), action)) {
                //TODO
                if (callbackData.getStartRepairTime() != null) {
                    repairRecord.setRepairStartDate(callbackData.getStartRepairTime());
                }
            }
            repairRecord.setRepairEndDate(callbackData.getEndRepairTime());
            repairRecord.setUpdateBy("一键报修");
            completeRepair(repairRecord);
        }
        return repairRecord;
    }

    /**
     * callRepair
     *
     * @param devMaintenWork 报修详情
     * @return
     */
    @Override
    public boolean callRepair(DevMaintenWorkEntity devMaintenWork) {
        // 维修状态
        devMaintenWork.setDevStatus(DevRepairTicketStage.CALL_REPAIR);
        // ERMS流程报修
        devMaintenWork.setSource(DeviceTicketSource.SYSTEM.name());
        devMaintenWork.setProcessNode(0);
        boolean callRepairResult = devMaintenWorkService.save(devMaintenWork) > 0;
        if (callRepairResult) {
            // 1、创建维修记录
            DevMaintenRepairEntity repairRecord = new DevMaintenRepairEntity();
            repairRecord.setMaintenRecordId(devMaintenWork.getId());
            repairRecord.setDevId(devMaintenWork.getDevId());
            repairRecord.setUploadDate(devMaintenWork.getUploadDate());
            repairRecord.setFaultCategoryId(devMaintenWork.getFaultCategoryId());
            repairRecord.setFaultId(devMaintenWork.getFaultId());
            repairRecord.setFaultCode(devMaintenWork.getFaultCode());
            repairRecord.setFaultDesc(devMaintenWork.getFaultDesc());
            repairRecord.setSource(devMaintenWork.getSource());
            devRepairRecordService.save(repairRecord);
            // 2、如果现场照片不为空，则保存
            List<String> faultImages = devMaintenWork.getFaultImages();
            if (CollectionUtil.isNotEmpty(faultImages)) {
                ticketLiveImageService.batchUpdateTicketImages(devMaintenWork.getId(), "REPAIR", "维修前", faultImages);
            }
        }
        return callRepairResult;
    }

    @Override
    public boolean callRepair(DevRepairRecordEntity callRepairParam) {
        callRepairParam.setDevStatus(DevRepairTicketStage.CALL_REPAIR);
        callRepairParam.setSource(DeviceTicketSource.SYSTEM.name());
        boolean callRepairResult = deviceRepairRecordService.save(callRepairParam);
        if (callRepairResult) {
            // 1、如果现场照片不为空，则保存
            List<String> faultImages = callRepairParam.getFaultImages();
            if (CollectionUtil.isNotEmpty(faultImages)) {
                ticketLiveImageService.batchUpdateTicketImages(callRepairParam.getId(), "REPAIR", "维修前", faultImages);
            }
        }
        return callRepairResult;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public DevMaintenWorkEntity doAdditionalRecording(DevMaintenRepairEntity devRepairRecord) {
        /*
            补录：先生成工单，然后在保存记录
         */
        DevMaintenWorkEntity devRepairTicket = new DevMaintenWorkEntity();
        devRepairTicket.setWorkshopId(devRepairRecord.getWorkshopId());
        devRepairTicket.setDevId(devRepairRecord.getDevId());
        devRepairTicket.setFaultCon(devRepairRecord.getRecordDescr());
        // 默认补录时工单已关闭
        devRepairTicket.setDevStatus(DevRepairTicketStage.CLOSE);
        devRepairTicket.setRepairUser(ShiroUtils.getUserId());
        devRepairTicket.setStartRepairTime(devRepairRecord.getRepairStartDate());
        devRepairTicket.setEndRepairTime(devRepairRecord.getRepairEndDate());
        devRepairTicket.setSource(DeviceTicketSource.SECOND.name());
        // 保存维护工单信息
        int saveNum = devMaintenWorkService.save(devRepairTicket);
        cn.hutool.core.lang.Assert.isTrue(saveNum == 1);
        devRepairRecord.setMaintenRecordId(devRepairTicket.getId());
        devRepairRecord.setSource(devRepairTicket.getSource());
        devRepairRecordService.save(devRepairRecord);
        return devRepairTicket;

    }

    @Override
    public DevRepairRecordEntity doAdditionalRecording(DevRepairRecordEntity repairRecord) {
        // 默认补录时工单已关闭
        repairRecord.setDevStatus(DevRepairTicketStage.CLOSE);
        repairRecord.setRepairUser(ShiroUtils.getUserId());
        repairRecord.setSource(DeviceTicketSource.SECOND.name());
        deviceRepairRecordService.save(repairRecord);
        return repairRecord;
    }

    /**
     * 更新维修记录中协助相关信息，包括协助人员、协助时间等信息
     *
     * @param ticketId       工单ID
     * @param assistPersonId 协助人员ID
     * @param nextHandleNode 下一处理节点
     */
    private void updateAssistInfo(String ticketId, String assistPersonId, int nextHandleNode) {
        DevMaintenRepairEntity repairRecord = devMaintenRepairDao.queryByTicketId(ticketId);
        if (repairRecord != null) {
            repairRecord.setOrderNo(nextHandleNode);
            if (nextHandleNode == 3) {
                repairRecord.setLevel3AssistUser(assistPersonId);
                repairRecord.setLevel3AssistStartTime(DateUtil.date());
            } else if (nextHandleNode == 2) {
                repairRecord.setLevel2AssistUser(assistPersonId);
                repairRecord.setLevel2AssistStartTime(DateUtil.date());
            }
            devRepairRecordService.update(repairRecord);
        }
    }

}
